#ifndef _TWOGRE_WINDOW_MANAGER_H_
#define _TWOGRE_WINDOW_MANAGER_H_

#include <map>
#include <vector>

#include "TwOgrePrerequisites.h"

#include "OgreColourValue.h"
#include "OgreRenderQueueListener.h"
#include "OgreRenderWindow.h"
#include "OgreSceneManager.h"
#include "OgreSingleton.h"
#include "OgreString.h"
#include "OgreWindowEventUtilities.h"

#include "OIS/OISMouse.h"
#include "OIS/OISKeyboard.h"

#include "TwOgreWindow.h"

namespace TwOgre{
	class Variable;

	enum FontSize
	{
		FONT_SMALL = 1,
		FONT_MEDIUM = 2,
		FONT_LARGE = 3
	};

	/**
	 * WindowManager.
	 * The WindowManager is responsible for creating, managing and detroying all Windows.
	 */
	class TwOgreExport WindowManager : public Ogre::RenderQueueListener, public Ogre::WindowEventListener, public Ogre::Singleton<WindowManager>
	{
	public:
		/**
		 * Constructor.
		 * @param renderWindow Pointer to the Ogre::RenderWindow to render into.
		 * @param sceneManager Ponter to the Ogre::SceneManager to associate the Windows with.
		 */
		WindowManager(Ogre::RenderWindow *renderWindow, Ogre::SceneManager *sceneManager);
		/** Destructor. */
		~WindowManager();

		/** Returns the Listener singleton object */
		static WindowManager& getSingleton();
		/** Returns a pointer to the Listener singleton object */
		static WindowManager* getSingletonPtr();

		/**
		 * CreateWindow.
		 * @param name Name used to refer to the Window, it must be unique.
		 * @param title Optional text for the Titlebar of the Window, if not supplied the name is used.
		 * @param windowColor Background hue of the window.
		 * @param help Text that describes this Window in the Help Window.
		 */
		Window* createWindow(const Ogre::String& name, const Ogre::String& title="",
			const Ogre::ColourValue& windowColor=Ogre::ColourValue::ZERO, const Ogre::String& help="");
		Window* createWindow(WindowParams& params);
		/**
		 * Destroys a Window.
		 * @param name Name of the Widnow to destroy.
		 */
		void destroyWindow(const Ogre::String& name);
		/**
		 * Destroys a Window.
		 * @param window Pointer to the Window to destroy.
		 */
		void destroyWindow(Window *window);

		/**
		 * Sets the font size for all Windows.
		 * @param size Can be FONT_SMALL, FONT_MEDIUM or FONT_LARGE
		 */
		void setFontSize(FontSize size);

		/** Notify the WindowManager of a MouseMoved event */
		bool injectMouseMoved(const OIS::MouseEvent& mouseEvent);
		/** Notify the WindowManager of a MousePressed event */
		bool injectMousePressed(const OIS::MouseEvent& mouseEvent, OIS::MouseButtonID id);
		/** Notify the WindowManager of a MouseReleased event */
		bool injectMouseReleased(const OIS::MouseEvent& mouseEvent, OIS::MouseButtonID id);

		/** Notify the WindowManager of a KeyPressed event */
		bool injectKeyPressed(const OIS::KeyEvent& keyEvent);
		/** Notify the WindowManager of a KeyReleased event */
		bool injectKeyReleased(const OIS::KeyEvent& keyEvent);

	private:
		virtual void renderQueueStarted(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& skipThisInvocation);
		virtual void renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& repeatThisInvocation){}

		virtual void windowResized(Ogre::RenderWindow* renderWindow);

		inline TwMouseButtonID convertOIStoTweakMouse(OIS::MouseButtonID id) const;
		int convertOIStoTweakKey(const OIS::KeyEvent& keyEvent) const;

		int mKeyModifiers;

		typedef std::map<Ogre::String, Window*> WindowMap;
		WindowMap mWindowMap;

		Ogre::RenderWindow *mRenderWindow;
		Ogre::SceneManager *mSceneManager;

		friend class Window;
	};
}; // End Namespace
#endif
